International Soccer

Data Source

The aim of this project is to analyze a dataset on international soccer from Kaggle. The dataset is from: https://www.kaggle.com/datasets/martj42/international-football-results-from-1872-to-2017

Getting started

knitr::opts_chunk$set(warning = FALSE, message = FALSE) 
rm(list=ls())

Let’s import the libraries and read in the data.

#install.packages('tidyverse')
library(tidyverse)

goal_data <- read_csv('goalscorers.csv',
                      col_types = cols(
                        date  = col_date("%Y-%m-%d"),
                        home_team = col_character(),
                        away_team = col_character(),
                        team = col_character(),
                        scorer = col_character(),
                        own_goal = col_logical(),
                        penalty = col_logical()))

results <- read_csv('results.csv')
Rows: 44353 Columns: 9── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (5): home_team, away_team, tournament, city, country
dbl  (2): home_score, away_score
lgl  (1): neutral
date (1): date
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Exploring the data

Let’s filter the data into the last 20 years (games in 2002 and later).

library(lubridate)
library(ggplot2)

recent_goals <- goal_data %>%
  #filter(date >= '2002-01-01')
  filter(year(date) >= 2002)

Let’s check the starting timeframe of our data.

min(recent_goals$date)
[1] "2002-01-18"

Research Question 1

Question: Which teams had the most goals?

Ideally, we would normalize the number of goals by the number of games played. In this case, we are just calculating the total number of goals scored.


q1 = recent_goals %>%
  group_by(team) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals,
            .groups="drop") %>%
   slice_max(scores, n=20) %>% # this chooses the top 20 rows according to the scores field
  mutate(`Country Status` = ifelse(team=="Germany", "Top", "Other")) %>%
ggplot(aes(y=reorder(team, scores), x=scores)) +
  geom_col(aes(fill=`Country Status`)) + # highlights Germany
  theme_classic() +
  labs(y="", x="",
       title="Top 20 Goal Scoring Teams 2002-2023 (Total Scores)") +
  scale_fill_manual(name="",
                    breaks=c("Top", "Other"),
                    values=c("darkred", "grey50"))+
  geom_text(aes(x=scores-20, 
                label=scores),
            color="white") +
  theme(legend.position = "none",
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.line.x = element_blank())

ggplotly(q1)
NA

Research Question 2

Question Which individuals are the best at scoring? Which players scored the most own goals?


library(ggplot2)
q2 = recent_goals %>%
  group_by(scorer) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals,
            .groups="drop") %>%
   slice_max(scores, n=20) %>% # this chooses the top 20 rows according to the scores field
  mutate(`Top Player` = ifelse(scorer=="Cristiano Ronaldo", "Top", "Other")) %>%
ggplot(aes(y=reorder(scorer, scores), x=scores)) +
  geom_col(aes(fill=`Top Player`)) + # highlights Ronaldo
  theme_classic() +
  labs(y="", x="",
       title="Top 20 Goal Scorers 2002-2023 (Total Scores)") +
  scale_fill_manual(name="",
                    breaks=c("Top", "Other"),
                    values=c("darkred", "grey50"))+
  geom_text(aes(x=scores-20, 
                label=scores),
            color="white") +
  theme(legend.position = "none",
        axis.text.x = element_blank(),
        axis.ticks.x = element_blank(),
        axis.line.x = element_blank())

ggplotly(q2)
NA

Research Question 3

Question: What is the relationship between own goals + penalties?

This chart shows the relationship/correlation between own goals and penalties.

library(plotly)

p3 <- recent_goals %>%
  group_by(team) %>%
  summarise(num_goals = n(),
            `Own Goals` = sum(ifelse(own_goal, 1, 0)),
            Penalties = sum(ifelse(penalty, 1, 0)),
            scores = num_goals - `Own Goals`) %>%
  ggplot(aes(x=Penalties, y=`Own Goals`,
             text=paste("scores: ", scores," out of ",num_goals, sep="" ))) +
  geom_point(color="royalblue", alpha=0.5, aes(size=num_goals)) + theme_classic() +
  labs(size="Number of Scores", y="Own Goals", x="Penalties") +
  theme(legend.position = "bottom")

ggplotly(p3)
NA

Lets think about what is driving this relationship?

In the above chart, we can see a positive linear relationship between own goals and penalties. This means that as the frequency of own goals increases, so does the frequency of goals scored via penalties.

One possible explanation for this relationship could be that teams that are more likely to make mistakes leading to own goals may also be more likely to commit fouls resulting in penalties. Alternatively, it could be that teams who are more likely to be awarded penalties may also be more likely to have own goals scored against them due to defensive mistakes or bad luck.

Research Question 4

Question: Has the number of own goals changed over the years

g2 <- recent_goals %>%
  mutate(`Goal Year` = year(date)) %>%
  group_by(`Goal Year`) %>%
  summarise(`Own Goals` = sum(ifelse(own_goal, 1, 0))) %>%
  ggplot(aes(x=`Goal Year`, y=`Own Goals`)) +
  geom_area(fill="royalblue", stat="identity") +
  theme_classic()

ggplotly(g2)

We can clearly see that the number of own goals saw a sharp spike in 2019 and 2021.

Research Question 5

Question: When are the most goals scored during the game?

Area chart

recent_goals %>%
  group_by(minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_area(fill="royalblue", alpha=0.5) + theme_classic() +
  geom_vline(xintercept = 45, linetype=3) + 
  geom_vline(xintercept = 90, linetype=3) + 
  annotate("text", x=73, y=50, label="End of Regulation") +
  annotate("text", x=35, y=50, label="Half-time")

Question: When are the most goals scored by United States, Canada, Brazil, Argentina and France during the game? Multiple line/area chart

recent_goals %>%
  filter(team %in% c("United States", "Canada",
                     "Brazil", "Argentina", "France")) %>%
  group_by(minute, team) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  ggplot(aes(x=minute, y=scores, group=team)) +
  geom_line(aes(color=team), alpha=0.5) + theme_classic() +
  geom_vline(xintercept = 90) + 
  scale_color_brewer(palette="Blues") +
  annotate("text", x=60, y=30, label="End of Regulation")
`summarise()` has grouped output by 'minute'. You can override using the `.groups` argument.

Multiple area chart Use the stat=“identity” to make a non-stacked area chart.

# FACET
recent_goals %>%
  group_by(team, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  filter(team %in% c("United States", "France", "Brazil", "Argentina", "Canada")) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_area(aes(fill=team), position="identity",alpha=0.5) +
  scale_fill_brewer(palette = "Set1") +
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  #annotate("text", x=77, y=30, label="End of Regulation") +
  #annotate("text", x=35, y=30, label="Half time") +
  theme_classic() + theme(legend.position = "bottom") +
  labs(x="Minute", title="By Minute Goals for Several Countries")
`summarise()` has grouped output by 'team'. You can override using the `.groups` argument.

Multiple line chart for selected teams

# FACET
recent_goals %>%
  group_by(team, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  filter(team %in% c("United States", "France", "Brazil", "Argentina", "Canada")) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_line(aes(color=team)) +
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  #annotate("text", x=77, y=30, label="End of Regulation") +
  #annotate("text", x=35, y=30, label="Half time") +
  theme_classic() + theme(legend.position = "bottom") +
  labs(x="Minute", title="By Minute Goals for Several Countries")
`summarise()` has grouped output by 'team'. You can override using the `.groups` argument.

Lets visualise this using facet_wrap, which creates a separate chart for each team. Multiple line chart with a facet_wrap for selected teams

# FACET
recent_goals %>%
  group_by(team, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  filter(team %in% c("United States", "France", "Brazil", "Argentina", "Belgium")) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_line(aes(color=team)) +
  facet_wrap(~team) +
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  #annotate("text", x=77, y=30, label="End of Regulation") +
  #annotate("text", x=35, y=30, label="Half time") +
  theme_classic() + theme(legend.position = "bottom") +
  labs(x="Minute", title="By Minute Goals for Several Countries")
`summarise()` has grouped output by 'team'. You can override using the `.groups` argument.

Research Question 5

Question: Compare minute-by-minute goals scored by United States, Belgium, Brazil, Argentina and France during the game. Choosing a categorical transition variable: https://gganimate.com/reference/transition_states.html

library(gganimate)
g2 = recent_goals %>%
  group_by(team, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  filter(team %in% c("United States", "France", "Brazil", "Argentina", "Belgium")) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_area(aes(fill=team)) +
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  theme_classic() + theme(legend.position = "bottom") +
  labs(x="Minute", 
  title="By Minute Goals for Several Countries: {closest_state}") +
  transition_states(team) 
`summarise()` has grouped output by 'team'. You can override using the `.groups` argument.
animate(g2, renderer = gifski_renderer())

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!

If we want to manually choose the transition: https://gganimate.com/reference/transition_manual.html


library(tidyverse)
library(gganimate)
p3 <- recent_goals %>%
  mutate(minute = as.factor(minute)) %>%
  group_by(team, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  filter(team %in% c("United States", "France", "Brazil", "Argentina", "Belgium")) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_col(aes(fill=team)) +
  #facet_wrap(~minute) +
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  #annotate("text", x=77, y=30, label="End of Regulation") +
  #annotate("text", x=35, y=30, label="Half time") +
  theme_classic() + theme(legend.position = "bottom") +
  scale_x_discrete(breaks=as.character(seq(0,125,5))) +
  scale_y_continuous(expand=c(0,0)) +
  labs(x="Minute", title="By Minute Goals for Several Countries: {current_frame }") +
  transition_manual(minute , cumulative=TRUE)
`summarise()` has grouped output by 'team'. You can override using the `.groups` argument.
animate(p3, renderer = gifski_renderer())

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!

Research Question 6

Question: Visualise, for each year individually, the minute-by-minute goals scored by all countries during the game. Choosing a date: https://gganimate.com/reference/transition_time.html

library(gganimate)
library(lubridate)
#install.packages('transformr')
p4<- recent_goals %>%
  mutate(game_year = year(date)) %>%
  group_by(game_year, minute) %>%
  summarise(num_goals = n(),
            own_goals = sum(ifelse(own_goal, 1, 0)),
            scores = num_goals - own_goals) %>%
  ggplot(aes(x=minute, y=scores)) +
  geom_col()+ 
  geom_vline(xintercept = 90, linetype=3) +
  geom_vline(xintercept = 45, linetype=3) +
  #annotate("text", x=77, y=30, label="End of Regulation") +
  #annotate("text", x=35, y=30, label="Half time") +
  theme_classic() + 
  theme(legend.position = "bottom") +
  labs(x="Minute", title="By Minute Goals for Several Countries: {round(stat(frame_time), digits=0)}") +
  transition_time(game_year) + 
  ease_aes('linear')
`summarise()` has grouped output by 'game_year'. You can override using the `.groups` argument.
animate(p4, renderer = gifski_renderer())

Inserting image 1 at 0.00s (1%)...
Inserting image 2 at 0.10s (2%)...
Inserting image 3 at 0.20s (3%)...
Inserting image 4 at 0.30s (4%)...
Inserting image 5 at 0.40s (5%)...
Inserting image 6 at 0.50s (6%)...
Inserting image 7 at 0.60s (7%)...
Inserting image 8 at 0.70s (8%)...
Inserting image 9 at 0.80s (9%)...
Inserting image 10 at 0.90s (10%)...
Inserting image 11 at 1.00s (11%)...
Inserting image 12 at 1.10s (12%)...
Inserting image 13 at 1.20s (13%)...
Inserting image 14 at 1.30s (14%)...
Inserting image 15 at 1.40s (15%)...
Inserting image 16 at 1.50s (16%)...
Inserting image 17 at 1.60s (17%)...
Inserting image 18 at 1.70s (18%)...
Inserting image 19 at 1.80s (19%)...
Inserting image 20 at 1.90s (20%)...
Inserting image 21 at 2.00s (21%)...
Inserting image 22 at 2.10s (22%)...
Inserting image 23 at 2.20s (23%)...
Inserting image 24 at 2.30s (24%)...
Inserting image 25 at 2.40s (25%)...
Inserting image 26 at 2.50s (26%)...
Inserting image 27 at 2.60s (27%)...
Inserting image 28 at 2.70s (28%)...
Inserting image 29 at 2.80s (29%)...
Inserting image 30 at 2.90s (30%)...
Inserting image 31 at 3.00s (31%)...
Inserting image 32 at 3.10s (32%)...
Inserting image 33 at 3.20s (33%)...
Inserting image 34 at 3.30s (34%)...
Inserting image 35 at 3.40s (35%)...
Inserting image 36 at 3.50s (36%)...
Inserting image 37 at 3.60s (37%)...
Inserting image 38 at 3.70s (38%)...
Inserting image 39 at 3.80s (39%)...
Inserting image 40 at 3.90s (40%)...
Inserting image 41 at 4.00s (41%)...
Inserting image 42 at 4.10s (42%)...
Inserting image 43 at 4.20s (43%)...
Inserting image 44 at 4.30s (44%)...
Inserting image 45 at 4.40s (45%)...
Inserting image 46 at 4.50s (46%)...
Inserting image 47 at 4.60s (47%)...
Inserting image 48 at 4.70s (48%)...
Inserting image 49 at 4.80s (49%)...
Inserting image 50 at 4.90s (50%)...
Inserting image 51 at 5.00s (51%)...
Inserting image 52 at 5.10s (52%)...
Inserting image 53 at 5.20s (53%)...
Inserting image 54 at 5.30s (54%)...
Inserting image 55 at 5.40s (55%)...
Inserting image 56 at 5.50s (56%)...
Inserting image 57 at 5.60s (57%)...
Inserting image 58 at 5.70s (58%)...
Inserting image 59 at 5.80s (59%)...
Inserting image 60 at 5.90s (60%)...
Inserting image 61 at 6.00s (61%)...
Inserting image 62 at 6.10s (62%)...
Inserting image 63 at 6.20s (63%)...
Inserting image 64 at 6.30s (64%)...
Inserting image 65 at 6.40s (65%)...
Inserting image 66 at 6.50s (66%)...
Inserting image 67 at 6.60s (67%)...
Inserting image 68 at 6.70s (68%)...
Inserting image 69 at 6.80s (69%)...
Inserting image 70 at 6.90s (70%)...
Inserting image 71 at 7.00s (71%)...
Inserting image 72 at 7.10s (72%)...
Inserting image 73 at 7.20s (73%)...
Inserting image 74 at 7.30s (74%)...
Inserting image 75 at 7.40s (75%)...
Inserting image 76 at 7.50s (76%)...
Inserting image 77 at 7.60s (77%)...
Inserting image 78 at 7.70s (78%)...
Inserting image 79 at 7.80s (79%)...
Inserting image 80 at 7.90s (80%)...
Inserting image 81 at 8.00s (81%)...
Inserting image 82 at 8.10s (82%)...
Inserting image 83 at 8.20s (83%)...
Inserting image 84 at 8.30s (84%)...
Inserting image 85 at 8.40s (85%)...
Inserting image 86 at 8.50s (86%)...
Inserting image 87 at 8.60s (87%)...
Inserting image 88 at 8.70s (88%)...
Inserting image 89 at 8.80s (89%)...
Inserting image 90 at 8.90s (90%)...
Inserting image 91 at 9.00s (91%)...
Inserting image 92 at 9.10s (92%)...
Inserting image 93 at 9.20s (93%)...
Inserting image 94 at 9.30s (94%)...
Inserting image 95 at 9.40s (95%)...
Inserting image 96 at 9.50s (96%)...
Inserting image 97 at 9.60s (97%)...
Inserting image 98 at 9.70s (98%)...
Inserting image 99 at 9.80s (99%)...
Inserting image 100 at 9.90s (100%)...
Encoding to gif... done!
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOiBkZWZhdWx0CiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKIyMgSW50ZXJuYXRpb25hbCBTb2NjZXIKCiMjIyBEYXRhIFNvdXJjZQoKVGhlIGFpbSBvZiB0aGlzIHByb2plY3QgaXMgdG8gYW5hbHl6ZSBhIGRhdGFzZXQgb24gaW50ZXJuYXRpb25hbCBzb2NjZXIgZnJvbSBLYWdnbGUuIFRoZSBkYXRhc2V0IGlzIGZyb206IGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvbWFydGo0Mi9pbnRlcm5hdGlvbmFsLWZvb3RiYWxsLXJlc3VsdHMtZnJvbS0xODcyLXRvLTIwMTcKCiMjIyBHZXR0aW5nIHN0YXJ0ZWQKCmBgYHtyfQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIApybShsaXN0PWxzKCkpCmBgYAoKTGV0J3MgaW1wb3J0IHRoZSBsaWJyYXJpZXMgYW5kIHJlYWQgaW4gdGhlIGRhdGEuCmBgYHtyfQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90MikKCmdvYWxfZGF0YSA8LSByZWFkX2NzdignZ29hbHNjb3JlcnMuY3N2JywKICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGNvbHMoCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGUgID0gY29sX2RhdGUoIiVZLSVtLSVkIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGhvbWVfdGVhbSA9IGNvbF9jaGFyYWN0ZXIoKSwKICAgICAgICAgICAgICAgICAgICAgICAgYXdheV90ZWFtID0gY29sX2NoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgICB0ZWFtID0gY29sX2NoYXJhY3RlcigpLAogICAgICAgICAgICAgICAgICAgICAgICBzY29yZXIgPSBjb2xfY2hhcmFjdGVyKCksCiAgICAgICAgICAgICAgICAgICAgICAgIG93bl9nb2FsID0gY29sX2xvZ2ljYWwoKSwKICAgICAgICAgICAgICAgICAgICAgICAgcGVuYWx0eSA9IGNvbF9sb2dpY2FsKCkpKQoKcmVzdWx0cyA8LSByZWFkX2NzdigncmVzdWx0cy5jc3YnKQoKYGBgCgojIyMgRXhwbG9yaW5nIHRoZSBkYXRhCkxldCdzIGZpbHRlciB0aGUgZGF0YSBpbnRvIHRoZSBsYXN0IDIwIHllYXJzIChnYW1lcyBpbiAyMDAyIGFuZCBsYXRlcikuCmBgYHtyfQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCnJlY2VudF9nb2FscyA8LSBnb2FsX2RhdGEgJT4lCiAgI2ZpbHRlcihkYXRlID49ICcyMDAyLTAxLTAxJykKICBmaWx0ZXIoeWVhcihkYXRlKSA+PSAyMDAyKQoKYGBgCgpMZXQncyBjaGVjayB0aGUgc3RhcnRpbmcgdGltZWZyYW1lIG9mIG91ciBkYXRhLgpgYGB7cn0KbWluKHJlY2VudF9nb2FscyRkYXRlKQoKYGBgCgojIyMjIFJlc2VhcmNoIFF1ZXN0aW9uIDEKUXVlc3Rpb246ICpXaGljaCB0ZWFtcyBoYWQgdGhlIG1vc3QgZ29hbHM/KgoKSWRlYWxseSwgd2Ugd291bGQgbm9ybWFsaXplIHRoZSBudW1iZXIgb2YgZ29hbHMgYnkgdGhlIG51bWJlciBvZiBnYW1lcyBwbGF5ZWQuIEluIHRoaXMgY2FzZSwgd2UgYXJlIGp1c3QgY2FsY3VsYXRpbmcgdGhlIHRvdGFsIG51bWJlciBvZiBnb2FscyBzY29yZWQuCmBgYHtyfQoKcTEgPSByZWNlbnRfZ29hbHMgJT4lCiAgZ3JvdXBfYnkodGVhbSkgJT4lCiAgc3VtbWFyaXNlKG51bV9nb2FscyA9IG4oKSwKICAgICAgICAgICAgb3duX2dvYWxzID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpLAogICAgICAgICAgICBzY29yZXMgPSBudW1fZ29hbHMgLSBvd25fZ29hbHMsCiAgICAgICAgICAgIC5ncm91cHM9ImRyb3AiKSAlPiUKICAgc2xpY2VfbWF4KHNjb3Jlcywgbj0yMCkgJT4lICMgdGhpcyBjaG9vc2VzIHRoZSB0b3AgMjAgcm93cyBhY2NvcmRpbmcgdG8gdGhlIHNjb3JlcyBmaWVsZAogIG11dGF0ZShgQ291bnRyeSBTdGF0dXNgID0gaWZlbHNlKHRlYW09PSJHZXJtYW55IiwgIlRvcCIsICJPdGhlciIpKSAlPiUKZ2dwbG90KGFlcyh5PXJlb3JkZXIodGVhbSwgc2NvcmVzKSwgeD1zY29yZXMpKSArCiAgZ2VvbV9jb2woYWVzKGZpbGw9YENvdW50cnkgU3RhdHVzYCkpICsgIyBoaWdobGlnaHRzIEdlcm1hbnkKICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeT0iIiwgeD0iIiwKICAgICAgIHRpdGxlPSJUb3AgMjAgR29hbCBTY29yaW5nIFRlYW1zIDIwMDItMjAyMyAoVG90YWwgU2NvcmVzKSIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSIiLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKCJUb3AiLCAiT3RoZXIiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiZGFya3JlZCIsICJncmV5NTAiKSkrCiAgZ2VvbV90ZXh0KGFlcyh4PXNjb3Jlcy0yMCwgCiAgICAgICAgICAgICAgICBsYWJlbD1zY29yZXMpLAogICAgICAgICAgICBjb2xvcj0id2hpdGUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCmdncGxvdGx5KHExKQoKYGBgCgojIyMjIFJlc2VhcmNoIFF1ZXN0aW9uIDIKUXVlc3Rpb24gKldoaWNoIGluZGl2aWR1YWxzIGFyZSB0aGUgYmVzdCBhdCBzY29yaW5nPyBXaGljaCBwbGF5ZXJzIHNjb3JlZCB0aGUgbW9zdCBvd24gZ29hbHM/KiAKYGBge3J9CgpsaWJyYXJ5KGdncGxvdDIpCnEyID0gcmVjZW50X2dvYWxzICU+JQogIGdyb3VwX2J5KHNjb3JlcikgJT4lCiAgc3VtbWFyaXNlKG51bV9nb2FscyA9IG4oKSwKICAgICAgICAgICAgb3duX2dvYWxzID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpLAogICAgICAgICAgICBzY29yZXMgPSBudW1fZ29hbHMgLSBvd25fZ29hbHMsCiAgICAgICAgICAgIC5ncm91cHM9ImRyb3AiKSAlPiUKICAgc2xpY2VfbWF4KHNjb3Jlcywgbj0yMCkgJT4lICMgdGhpcyBjaG9vc2VzIHRoZSB0b3AgMjAgcm93cyBhY2NvcmRpbmcgdG8gdGhlIHNjb3JlcyBmaWVsZAogIG11dGF0ZShgVG9wIFBsYXllcmAgPSBpZmVsc2Uoc2NvcmVyPT0iQ3Jpc3RpYW5vIFJvbmFsZG8iLCAiVG9wIiwgIk90aGVyIikpICU+JQpnZ3Bsb3QoYWVzKHk9cmVvcmRlcihzY29yZXIsIHNjb3JlcyksIHg9c2NvcmVzKSkgKwogIGdlb21fY29sKGFlcyhmaWxsPWBUb3AgUGxheWVyYCkpICsgIyBoaWdobGlnaHRzIFJvbmFsZG8KICB0aGVtZV9jbGFzc2ljKCkgKwogIGxhYnMoeT0iIiwgeD0iIiwKICAgICAgIHRpdGxlPSJUb3AgMjAgR29hbCBTY29yZXJzIDIwMDItMjAyMyAoVG90YWwgU2NvcmVzKSIpICsKICBzY2FsZV9maWxsX21hbnVhbChuYW1lPSIiLAogICAgICAgICAgICAgICAgICAgIGJyZWFrcz1jKCJUb3AiLCAiT3RoZXIiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiZGFya3JlZCIsICJncmV5NTAiKSkrCiAgZ2VvbV90ZXh0KGFlcyh4PXNjb3Jlcy0yMCwgCiAgICAgICAgICAgICAgICBsYWJlbD1zY29yZXMpLAogICAgICAgICAgICBjb2xvcj0id2hpdGUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUueCA9IGVsZW1lbnRfYmxhbmsoKSkKCmdncGxvdGx5KHEyKQoKYGBgCgoKIyMjIyBSZXNlYXJjaCBRdWVzdGlvbiAzClF1ZXN0aW9uOiAqV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gb3duIGdvYWxzICsgcGVuYWx0aWVzPyoKClRoaXMgY2hhcnQgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcC9jb3JyZWxhdGlvbiBiZXR3ZWVuIG93biBnb2FscyBhbmQgcGVuYWx0aWVzLiAKYGBge3J9CmxpYnJhcnkocGxvdGx5KQoKcDMgPC0gcmVjZW50X2dvYWxzICU+JQogIGdyb3VwX2J5KHRlYW0pICU+JQogIHN1bW1hcmlzZShudW1fZ29hbHMgPSBuKCksCiAgICAgICAgICAgIGBPd24gR29hbHNgID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpLAogICAgICAgICAgICBQZW5hbHRpZXMgPSBzdW0oaWZlbHNlKHBlbmFsdHksIDEsIDApKSwKICAgICAgICAgICAgc2NvcmVzID0gbnVtX2dvYWxzIC0gYE93biBHb2Fsc2ApICU+JQogIGdncGxvdChhZXMoeD1QZW5hbHRpZXMsIHk9YE93biBHb2Fsc2AsCiAgICAgICAgICAgICB0ZXh0PXBhc3RlKCJzY29yZXM6ICIsIHNjb3JlcywiIG91dCBvZiAiLG51bV9nb2Fscywgc2VwPSIiICkpKSArCiAgZ2VvbV9wb2ludChjb2xvcj0icm95YWxibHVlIiwgYWxwaGE9MC41LCBhZXMoc2l6ZT1udW1fZ29hbHMpKSArIHRoZW1lX2NsYXNzaWMoKSArCiAgbGFicyhzaXplPSJOdW1iZXIgb2YgU2NvcmVzIiwgeT0iT3duIEdvYWxzIiwgeD0iUGVuYWx0aWVzIikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dwbG90bHkocDMpCgpgYGAKCipMZXRzIHRoaW5rIGFib3V0IHdoYXQgaXMgZHJpdmluZyB0aGlzIHJlbGF0aW9uc2hpcD8qCgpJbiB0aGUgYWJvdmUgY2hhcnQsIHdlIGNhbiBzZWUgYSBwb3NpdGl2ZSBsaW5lYXIgcmVsYXRpb25zaGlwIGJldHdlZW4gb3duIGdvYWxzIGFuZCBwZW5hbHRpZXMuIFRoaXMgbWVhbnMgdGhhdCBhcyB0aGUgZnJlcXVlbmN5IG9mIG93biBnb2FscyBpbmNyZWFzZXMsIHNvIGRvZXMgdGhlIGZyZXF1ZW5jeSBvZiBnb2FscyBzY29yZWQgdmlhIHBlbmFsdGllcy4KCk9uZSBwb3NzaWJsZSBleHBsYW5hdGlvbiBmb3IgdGhpcyByZWxhdGlvbnNoaXAgY291bGQgYmUgdGhhdCB0ZWFtcyB0aGF0IGFyZSBtb3JlIGxpa2VseSB0byBtYWtlIG1pc3Rha2VzIGxlYWRpbmcgdG8gb3duIGdvYWxzIG1heSBhbHNvIGJlIG1vcmUgbGlrZWx5IHRvIGNvbW1pdCBmb3VscyByZXN1bHRpbmcgaW4gcGVuYWx0aWVzLiBBbHRlcm5hdGl2ZWx5LCBpdCBjb3VsZCBiZSB0aGF0IHRlYW1zIHdobyBhcmUgbW9yZSBsaWtlbHkgdG8gYmUgYXdhcmRlZCBwZW5hbHRpZXMgbWF5IGFsc28gYmUgbW9yZSBsaWtlbHkgdG8gaGF2ZSBvd24gZ29hbHMgc2NvcmVkIGFnYWluc3QgdGhlbSBkdWUgdG8gZGVmZW5zaXZlIG1pc3Rha2VzIG9yIGJhZCBsdWNrLgoKCiMjIyMgUmVzZWFyY2ggUXVlc3Rpb24gNApRdWVzdGlvbjogKkhhcyB0aGUgbnVtYmVyIG9mIG93biBnb2FscyBjaGFuZ2VkIG92ZXIgdGhlIHllYXJzKgoKYGBge3J9CmcyIDwtIHJlY2VudF9nb2FscyAlPiUKICBtdXRhdGUoYEdvYWwgWWVhcmAgPSB5ZWFyKGRhdGUpKSAlPiUKICBncm91cF9ieShgR29hbCBZZWFyYCkgJT4lCiAgc3VtbWFyaXNlKGBPd24gR29hbHNgID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9YEdvYWwgWWVhcmAsIHk9YE93biBHb2Fsc2ApKSArCiAgZ2VvbV9hcmVhKGZpbGw9InJveWFsYmx1ZSIsIHN0YXQ9ImlkZW50aXR5IikgKwogIHRoZW1lX2NsYXNzaWMoKQoKZ2dwbG90bHkoZzIpCmBgYAoKV2UgY2FuIGNsZWFybHkgc2VlIHRoYXQgdGhlIG51bWJlciBvZiBvd24gZ29hbHMgc2F3IGEgc2hhcnAgc3Bpa2UgaW4gMjAxOSBhbmQgMjAyMS4KCiMjIyMgUmVzZWFyY2ggUXVlc3Rpb24gNQpRdWVzdGlvbjogKldoZW4gYXJlIHRoZSBtb3N0IGdvYWxzIHNjb3JlZCBkdXJpbmcgdGhlIGdhbWU/KgoKKipBcmVhIGNoYXJ0KioKYGBge3J9CnJlY2VudF9nb2FscyAlPiUKICBncm91cF9ieShtaW51dGUpICU+JQogIHN1bW1hcmlzZShudW1fZ29hbHMgPSBuKCksCiAgICAgICAgICAgIG93bl9nb2FscyA9IHN1bShpZmVsc2Uob3duX2dvYWwsIDEsIDApKSwKICAgICAgICAgICAgc2NvcmVzID0gbnVtX2dvYWxzIC0gb3duX2dvYWxzKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bWludXRlLCB5PXNjb3JlcykpICsKICBnZW9tX2FyZWEoZmlsbD0icm95YWxibHVlIiwgYWxwaGE9MC41KSArIHRoZW1lX2NsYXNzaWMoKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNDUsIGxpbmV0eXBlPTMpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGxpbmV0eXBlPTMpICsgCiAgYW5ub3RhdGUoInRleHQiLCB4PTczLCB5PTUwLCBsYWJlbD0iRW5kIG9mIFJlZ3VsYXRpb24iKSArCiAgYW5ub3RhdGUoInRleHQiLCB4PTM1LCB5PTUwLCBsYWJlbD0iSGFsZi10aW1lIikKCmBgYAoKUXVlc3Rpb246ICpXaGVuIGFyZSB0aGUgbW9zdCBnb2FscyBzY29yZWQgYnkgVW5pdGVkIFN0YXRlcywgQ2FuYWRhLCBCcmF6aWwsIEFyZ2VudGluYSBhbmQgRnJhbmNlIGR1cmluZyB0aGUgZ2FtZT8qCioqTXVsdGlwbGUgbGluZS9hcmVhIGNoYXJ0KioKYGBge3J9CnJlY2VudF9nb2FscyAlPiUKICBmaWx0ZXIodGVhbSAlaW4lIGMoIlVuaXRlZCBTdGF0ZXMiLCAiQ2FuYWRhIiwKICAgICAgICAgICAgICAgICAgICAgIkJyYXppbCIsICJBcmdlbnRpbmEiLCAiRnJhbmNlIikpICU+JQogIGdyb3VwX2J5KG1pbnV0ZSwgdGVhbSkgJT4lCiAgc3VtbWFyaXNlKG51bV9nb2FscyA9IG4oKSwKICAgICAgICAgICAgb3duX2dvYWxzID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpLAogICAgICAgICAgICBzY29yZXMgPSBudW1fZ29hbHMgLSBvd25fZ29hbHMpICU+JQogIGdncGxvdChhZXMoeD1taW51dGUsIHk9c2NvcmVzLCBncm91cD10ZWFtKSkgKwogIGdlb21fbGluZShhZXMoY29sb3I9dGVhbSksIGFscGhhPTAuNSkgKyB0aGVtZV9jbGFzc2ljKCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwKSArIAogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlPSJCbHVlcyIpICsKICBhbm5vdGF0ZSgidGV4dCIsIHg9NjAsIHk9MzAsIGxhYmVsPSJFbmQgb2YgUmVndWxhdGlvbiIpCgpgYGAKCioqTXVsdGlwbGUgYXJlYSBjaGFydCoqClVzZSB0aGUgc3RhdD0iaWRlbnRpdHkiIHRvIG1ha2UgYSBub24tc3RhY2tlZCBhcmVhIGNoYXJ0LgpgYGB7cn0KIyBGQUNFVApyZWNlbnRfZ29hbHMgJT4lCiAgZ3JvdXBfYnkodGVhbSwgbWludXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2dvYWxzID0gbigpLAogICAgICAgICAgICBvd25fZ29hbHMgPSBzdW0oaWZlbHNlKG93bl9nb2FsLCAxLCAwKSksCiAgICAgICAgICAgIHNjb3JlcyA9IG51bV9nb2FscyAtIG93bl9nb2FscykgJT4lCiAgZmlsdGVyKHRlYW0gJWluJSBjKCJVbml0ZWQgU3RhdGVzIiwgIkZyYW5jZSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkNhbmFkYSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bWludXRlLCB5PXNjb3JlcykpICsKICBnZW9tX2FyZWEoYWVzKGZpbGw9dGVhbSksIHBvc2l0aW9uPSJpZGVudGl0eSIsYWxwaGE9MC41KSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNDUsIGxpbmV0eXBlPTMpICsKICAjYW5ub3RhdGUoInRleHQiLCB4PTc3LCB5PTMwLCBsYWJlbD0iRW5kIG9mIFJlZ3VsYXRpb24iKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeD0zNSwgeT0zMCwgbGFiZWw9IkhhbGYgdGltZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGxhYnMoeD0iTWludXRlIiwgdGl0bGU9IkJ5IE1pbnV0ZSBHb2FscyBmb3IgU2V2ZXJhbCBDb3VudHJpZXMiKQoKYGBgCioqTXVsdGlwbGUgbGluZSBjaGFydCBmb3Igc2VsZWN0ZWQgdGVhbXMqKgpgYGB7cn0KIyBGQUNFVApyZWNlbnRfZ29hbHMgJT4lCiAgZ3JvdXBfYnkodGVhbSwgbWludXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2dvYWxzID0gbigpLAogICAgICAgICAgICBvd25fZ29hbHMgPSBzdW0oaWZlbHNlKG93bl9nb2FsLCAxLCAwKSksCiAgICAgICAgICAgIHNjb3JlcyA9IG51bV9nb2FscyAtIG93bl9nb2FscykgJT4lCiAgZmlsdGVyKHRlYW0gJWluJSBjKCJVbml0ZWQgU3RhdGVzIiwgIkZyYW5jZSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkNhbmFkYSIpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bWludXRlLCB5PXNjb3JlcykpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yPXRlYW0pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0NSwgbGluZXR5cGU9MykgKwogICNhbm5vdGF0ZSgidGV4dCIsIHg9NzcsIHk9MzAsIGxhYmVsPSJFbmQgb2YgUmVndWxhdGlvbiIpICsKICAjYW5ub3RhdGUoInRleHQiLCB4PTM1LCB5PTMwLCBsYWJlbD0iSGFsZiB0aW1lIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh4PSJNaW51dGUiLCB0aXRsZT0iQnkgTWludXRlIEdvYWxzIGZvciBTZXZlcmFsIENvdW50cmllcyIpCgpgYGAKCkxldHMgdmlzdWFsaXNlIHRoaXMgdXNpbmcgZmFjZXRfd3JhcCwgd2hpY2ggY3JlYXRlcyBhIHNlcGFyYXRlIGNoYXJ0IGZvciBlYWNoIHRlYW0uCioqTXVsdGlwbGUgbGluZSBjaGFydCB3aXRoIGEgZmFjZXRfd3JhcCBmb3Igc2VsZWN0ZWQgdGVhbXMqKgpgYGB7cn0KIyBGQUNFVApyZWNlbnRfZ29hbHMgJT4lCiAgZ3JvdXBfYnkodGVhbSwgbWludXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2dvYWxzID0gbigpLAogICAgICAgICAgICBvd25fZ29hbHMgPSBzdW0oaWZlbHNlKG93bl9nb2FsLCAxLCAwKSksCiAgICAgICAgICAgIHNjb3JlcyA9IG51bV9nb2FscyAtIG93bl9nb2FscykgJT4lCiAgZmlsdGVyKHRlYW0gJWluJSBjKCJVbml0ZWQgU3RhdGVzIiwgIkZyYW5jZSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkJlbGdpdW0iKSkgJT4lCiAgZ2dwbG90KGFlcyh4PW1pbnV0ZSwgeT1zY29yZXMpKSArCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj10ZWFtKSkgKwogIGZhY2V0X3dyYXAofnRlYW0pICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA5MCwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQ1LCBsaW5ldHlwZT0zKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeD03NywgeT0zMCwgbGFiZWw9IkVuZCBvZiBSZWd1bGF0aW9uIikgKwogICNhbm5vdGF0ZSgidGV4dCIsIHg9MzUsIHk9MzAsIGxhYmVsPSJIYWxmIHRpbWUiKSArCiAgdGhlbWVfY2xhc3NpYygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBsYWJzKHg9Ik1pbnV0ZSIsIHRpdGxlPSJCeSBNaW51dGUgR29hbHMgZm9yIFNldmVyYWwgQ291bnRyaWVzIikKCmBgYAoKIyMjIyBSZXNlYXJjaCBRdWVzdGlvbiA1ClF1ZXN0aW9uOiAqQ29tcGFyZSBtaW51dGUtYnktbWludXRlIGdvYWxzIHNjb3JlZCBieSBVbml0ZWQgU3RhdGVzLCBCZWxnaXVtLCBCcmF6aWwsIEFyZ2VudGluYSBhbmQgRnJhbmNlIGR1cmluZyB0aGUgZ2FtZS4qCkNob29zaW5nIGEgY2F0ZWdvcmljYWwgdHJhbnNpdGlvbiB2YXJpYWJsZTogaHR0cHM6Ly9nZ2FuaW1hdGUuY29tL3JlZmVyZW5jZS90cmFuc2l0aW9uX3N0YXRlcy5odG1sCmBgYHtyfQpsaWJyYXJ5KGdnYW5pbWF0ZSkKZzIgPSByZWNlbnRfZ29hbHMgJT4lCiAgZ3JvdXBfYnkodGVhbSwgbWludXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2dvYWxzID0gbigpLAogICAgICAgICAgICBvd25fZ29hbHMgPSBzdW0oaWZlbHNlKG93bl9nb2FsLCAxLCAwKSksCiAgICAgICAgICAgIHNjb3JlcyA9IG51bV9nb2FscyAtIG93bl9nb2FscykgJT4lCiAgZmlsdGVyKHRlYW0gJWluJSBjKCJVbml0ZWQgU3RhdGVzIiwgIkZyYW5jZSIsICJCcmF6aWwiLCAiQXJnZW50aW5hIiwgIkJlbGdpdW0iKSkgJT4lCiAgZ2dwbG90KGFlcyh4PW1pbnV0ZSwgeT1zY29yZXMpKSArCiAgZ2VvbV9hcmVhKGFlcyhmaWxsPXRlYW0pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0NSwgbGluZXR5cGU9MykgKwogIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh4PSJNaW51dGUiLCAKICB0aXRsZT0iQnkgTWludXRlIEdvYWxzIGZvciBTZXZlcmFsIENvdW50cmllczoge2Nsb3Nlc3Rfc3RhdGV9IikgKwogIHRyYW5zaXRpb25fc3RhdGVzKHRlYW0pIAoKYW5pbWF0ZShnMiwgcmVuZGVyZXIgPSBnaWZza2lfcmVuZGVyZXIoKSkKYGBgCgoqSWYgd2Ugd2FudCB0byBtYW51YWxseSBjaG9vc2UgdGhlIHRyYW5zaXRpb246IGh0dHBzOi8vZ2dhbmltYXRlLmNvbS9yZWZlcmVuY2UvdHJhbnNpdGlvbl9tYW51YWwuaHRtbCoKYGBge3J9CgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnZ2FuaW1hdGUpCnAzIDwtIHJlY2VudF9nb2FscyAlPiUKICBtdXRhdGUobWludXRlID0gYXMuZmFjdG9yKG1pbnV0ZSkpICU+JQogIGdyb3VwX2J5KHRlYW0sIG1pbnV0ZSkgJT4lCiAgc3VtbWFyaXNlKG51bV9nb2FscyA9IG4oKSwKICAgICAgICAgICAgb3duX2dvYWxzID0gc3VtKGlmZWxzZShvd25fZ29hbCwgMSwgMCkpLAogICAgICAgICAgICBzY29yZXMgPSBudW1fZ29hbHMgLSBvd25fZ29hbHMpICU+JQogIGZpbHRlcih0ZWFtICVpbiUgYygiVW5pdGVkIFN0YXRlcyIsICJGcmFuY2UiLCAiQnJhemlsIiwgIkFyZ2VudGluYSIsICJCZWxnaXVtIikpICU+JQogIGdncGxvdChhZXMoeD1taW51dGUsIHk9c2NvcmVzKSkgKwogIGdlb21fY29sKGFlcyhmaWxsPXRlYW0pKSArCiAgI2ZhY2V0X3dyYXAofm1pbnV0ZSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDkwLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gNDUsIGxpbmV0eXBlPTMpICsKICAjYW5ub3RhdGUoInRleHQiLCB4PTc3LCB5PTMwLCBsYWJlbD0iRW5kIG9mIFJlZ3VsYXRpb24iKSArCiAgI2Fubm90YXRlKCJ0ZXh0IiwgeD0zNSwgeT0zMCwgbGFiZWw9IkhhbGYgdGltZSIpICsKICB0aGVtZV9jbGFzc2ljKCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzPWFzLmNoYXJhY3RlcihzZXEoMCwxMjUsNSkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZD1jKDAsMCkpICsKICBsYWJzKHg9Ik1pbnV0ZSIsIHRpdGxlPSJCeSBNaW51dGUgR29hbHMgZm9yIFNldmVyYWwgQ291bnRyaWVzOiB7Y3VycmVudF9mcmFtZSB9IikgKwogIHRyYW5zaXRpb25fbWFudWFsKG1pbnV0ZSAsIGN1bXVsYXRpdmU9VFJVRSkKCmFuaW1hdGUocDMsIHJlbmRlcmVyID0gZ2lmc2tpX3JlbmRlcmVyKCkpCmBgYAoKIyMjIyBSZXNlYXJjaCBRdWVzdGlvbiA2ClF1ZXN0aW9uOiAqVmlzdWFsaXNlLCBmb3IgZWFjaCB5ZWFyIGluZGl2aWR1YWxseSwgdGhlIG1pbnV0ZS1ieS1taW51dGUgZ29hbHMgc2NvcmVkIGJ5IGFsbCBjb3VudHJpZXMgZHVyaW5nIHRoZSBnYW1lLioKQ2hvb3NpbmcgYSBkYXRlOiBodHRwczovL2dnYW5pbWF0ZS5jb20vcmVmZXJlbmNlL3RyYW5zaXRpb25fdGltZS5odG1sCmBgYHtyfQpsaWJyYXJ5KGdnYW5pbWF0ZSkKbGlicmFyeShsdWJyaWRhdGUpCiNpbnN0YWxsLnBhY2thZ2VzKCd0cmFuc2Zvcm1yJykKcDQ8LSByZWNlbnRfZ29hbHMgJT4lCiAgbXV0YXRlKGdhbWVfeWVhciA9IHllYXIoZGF0ZSkpICU+JQogIGdyb3VwX2J5KGdhbWVfeWVhciwgbWludXRlKSAlPiUKICBzdW1tYXJpc2UobnVtX2dvYWxzID0gbigpLAogICAgICAgICAgICBvd25fZ29hbHMgPSBzdW0oaWZlbHNlKG93bl9nb2FsLCAxLCAwKSksCiAgICAgICAgICAgIHNjb3JlcyA9IG51bV9nb2FscyAtIG93bl9nb2FscykgJT4lCiAgZ2dwbG90KGFlcyh4PW1pbnV0ZSwgeT1zY29yZXMpKSArCiAgZ2VvbV9jb2woKSsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gOTAsIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0NSwgbGluZXR5cGU9MykgKwogICNhbm5vdGF0ZSgidGV4dCIsIHg9NzcsIHk9MzAsIGxhYmVsPSJFbmQgb2YgUmVndWxhdGlvbiIpICsKICAjYW5ub3RhdGUoInRleHQiLCB4PTM1LCB5PTMwLCBsYWJlbD0iSGFsZiB0aW1lIikgKwogIHRoZW1lX2NsYXNzaWMoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgbGFicyh4PSJNaW51dGUiLCB0aXRsZT0iQnkgTWludXRlIEdvYWxzIGZvciBTZXZlcmFsIENvdW50cmllczoge3JvdW5kKHN0YXQoZnJhbWVfdGltZSksIGRpZ2l0cz0wKX0iKSArCiAgdHJhbnNpdGlvbl90aW1lKGdhbWVfeWVhcikgKyAKICBlYXNlX2FlcygnbGluZWFyJykKCmFuaW1hdGUocDQsIHJlbmRlcmVyID0gZ2lmc2tpX3JlbmRlcmVyKCkpCmBgYAoK